package com.gitee.l0km.codegen.base.generator;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.collections.ExtendedProperties;
import org.apache.velocity.exception.ResourceNotFoundException;
import org.apache.velocity.exception.VelocityException;
import org.apache.velocity.io.UnicodeInputStream;
import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
import org.apache.velocity.util.ClassUtils;
import org.apache.velocity.util.StringUtils;

/**
 * 支持多路径搜索的 ResourceLoader 实现<br>
 * 逻辑参照 FileResourceLoader 
 * @author guyadong
 *
 */
public class MultiClasspathResourceLoader extends ClasspathResourceLoader {
    /**
     * The paths to search for templates.
     */
    private List<String> paths = new ArrayList<String>();
    /** Shall we inspect unicode files to see what encoding they contain?. */
    private boolean unicode = false;
	public MultiClasspathResourceLoader() {
	}

	@SuppressWarnings("unchecked")
	@Override
	public void init(ExtendedProperties configuration) {
		paths.addAll( configuration.getVector("path") );
        // unicode files may have a BOM marker at the start, but Java
        // has problems recognizing the UTF-8 bom. Enabling unicode will
        // recognize all unicode boms.
        unicode = configuration.getBoolean("unicode", false);

        if (log.isDebugEnabled())
        {
            log.debug("Do unicode file recognition:  " + unicode);
        }

        if (log.isDebugEnabled())
        {
            // trim spaces from all paths
            StringUtils.trimStrings(paths);

            // this section lets tell people what paths we will be using
            int sz = paths.size();
            for( int i=0; i < sz; i++)
            {
                log.debug("MultiClasspathResourceLoader : adding path '" + (String) paths.get(i) + "'");
            }
            log.trace("MultiClasspathResourceLoader : initialization complete.");
        }
	}

	@Override
	public InputStream getResourceStream(String templateName) throws ResourceNotFoundException {
        if (org.apache.commons.lang.StringUtils.isEmpty(templateName))
        {
            throw new ResourceNotFoundException ("No template name provided");
        }
        String template = StringUtils.normalizePath(templateName);
        if ( template == null || template.length() == 0 )
        {
            String msg = "classpath resource error : argument " + template +
                " contains .. and may be trying to access " +
                "content outside of template root.  Rejected.";

            log.error("MultiClasspathResourceLoader : " + msg);

            throw new ResourceNotFoundException ( msg );
        }
        int size = paths.size();
        for (int i = 0; i < size; i++)
        {
            String path = (String) paths.get(i);
            InputStream inputStream = null;

            try
            {
                inputStream = findTemplate(path, template);
            }
            catch (IOException ioe)
            {
                String msg = "Exception while loading Template " + template;
                log.error(msg, ioe);
                throw new VelocityException(msg, ioe);
            }

            if (inputStream != null)
            {
                return inputStream;
            }
        }
        /*
         * We have now searched all the paths for
         * templates and we didn't find anything so
         * throw an exception.
         */
         throw new ResourceNotFoundException("MultiClasspathResourceLoader : cannot find " + template);
	}
    /**
     * Try to find a template given a normalized path.
     *
     * @param path a normalized path
     * @param template name of template to find
     * @return InputStream input stream that will be parsed
     *
     */
    private InputStream findTemplate(final String path, final String template)
        throws IOException
    {
            String filePath = StringUtils.normalizePath(getFile(path,template).getPath());

            InputStream in = null;
            try
            {
            	in = ClassUtils.getResourceAsStream( getClass(), filePath );
            	if(null ==in){
            		return null;
            	}
                if (unicode)
                {
                    UnicodeInputStream uis = null;

                    try
                    {
                        uis = new UnicodeInputStream(in, true);

                        if (log.isDebugEnabled())
                        {
                            log.debug("File Encoding for " + filePath + " is: " + uis.getEncodingFromStream());
                        }

                        return new BufferedInputStream(uis);
                    }
                    catch(IOException e)
                    {
                        closeQuiet(uis);
                        throw e;
                    }
                }
                else
                {
                    return new BufferedInputStream(in);
                }
            }
            catch (IOException e)
            {
                closeQuiet(in);
                throw e;
            }
    }
    /**
     * Create a File based on either a relative path if given, or absolute path otherwise
     */
    private File getFile(String path, String template)
    {

        File file = null;

        if("".equals(path))
        {
            file = new File( template );
        }
        else
        {
            /*
             *  if a / leads off, then just nip that :)
             */
            if (template.startsWith("/"))
            {
                template = template.substring(1);
            }

            file = new File ( path, template );
        }

        return file;
    }
    private void closeQuiet(final InputStream is)
    {
        if (is != null)
        {
            try
            {
                is.close();
            }
            catch(IOException ioe)
            {
                // Ignore
            }
        }
    }
}
